package com.kamikaze.docidset.impl;

import java.io.IOException;
import java.io.Serializable;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.kamikaze.lucenetrunk.search.DocIdSet;
import com.kamikaze.lucenetrunk.search.DocIdSetIterator;

public class AndDocIdSet extends ImmutableDocSet implements Serializable {
  private static final long serialVersionUID = 1L;

  private static transient Log log = LogFactory.getLog(OrDocIdSet.class);

  public class DescDocIdSetComparator implements Comparator<DocIdSetIterator>,
      Serializable {
    private static final long serialVersionUID = 1L;

    public int compare(DocIdSetIterator o1, DocIdSetIterator o2) {
      return o2.doc() - o1.doc();
    }

  }

  private List<DocIdSet> sets = null;
  private int nonNullSize; // excludes nulls
  
  public AndDocIdSet(List<DocIdSet> docSets) {
    this.sets = docSets;
    int size = 0;
    if (sets != null) {
      for(DocIdSet set : sets) {
        if(set != null) size++;
      }
    }
    nonNullSize = size;
  }

  class AndDocIdSetIterator extends DocIdSetIterator {
    int lastReturn = -1;
    boolean moreDoc = true;
    private DocIdSetIterator[] iterators = null;

    AndDocIdSetIterator() {
      if (nonNullSize < 1)
        throw new IllegalArgumentException("Minimum one iterator required");
    }

    private void initialize(int target) throws IOException {
      iterators = new DocIdSetIterator[nonNullSize];
      int j = 0;
      for (DocIdSet set : sets) {
        if (set != null) {
          DocIdSetIterator dcit = set.iterator();
          moreDoc &= dcit.skipTo(target);
          iterators[j++] = dcit;
        }
      }
    }

    @Override
    public int doc() {
      return lastReturn;
    }

    
    
    
    
    /*@Override 
    public boolean next() {
      
      if (itCnt > pq.size())
        return false;
      boolean more = true;
      DocIdSetIterator dcit = null;
      for(int i = 0; i< docSets.size();i++)
      {
        dcit = docSets.get(i);
        if(lastReturn < dcit.doc() )
        {
          lastReturn = dcit.doc();
          dcit.next();
        }
      }
      
      
      
    }*/
    
    
    @Override
    public boolean next() throws IOException {
      return skipTo(lastReturn + 1);
    }

    @Override
    public boolean skipTo(int target) throws IOException {

      if (!moreDoc) return false;
      
      if (target <= lastReturn) target = lastReturn + 1;

      if (iterators == null) initialize(target);
      
      int size = iterators.length;
      int i = 0;
      while (moreDoc && i < size) {
        DocIdSetIterator dcit = iterators[i];
        int docid = dcit.doc();
        if (docid < target) {
          moreDoc = dcit.skipTo(target);
          if (!moreDoc) break;

          docid = dcit.doc();
        }
        if (docid > target) {
          target = docid;
          i = 0;
        }
        else {
          i++;
        }
      }
      lastReturn = target;
      return moreDoc;
    }
  }

  public DocIdSetIterator iterator() {
    return new AndDocIdSetIterator();
  }
  
  /**
   * Find existence in the set
   * @return
   */
  @Override
  public int find(int val)
  {
    DocIdSetIterator finder = new AndDocIdSetIterator();
    try {
      finder.skipTo(val);
      if(finder.doc() == val)
          return finder.getCursor();
    } catch (IOException e) {
      return -1;
    }
    return -1;
  }
  
  
  
}
